﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public abstract class RobotComponent
{
    protected RobotComponent _parent = null;
    public virtual RobotComponent parent
    {
        get
        {
            return _parent;
        }
        set
        {
            if (_parent == value)
            {
                return;
            }
            if (_parent != null)
            {
                _parent.RemoveComponentFromList(this);
            }
            _parent = value;
            if (_parent != null)
            {
                _parent.AddComponentToList(this);
            }
        }
    }
    public virtual void RemoveFromParent()
    {
        parent = null;
    }
    protected List<RobotComponent> _children = new List<RobotComponent>();
    protected virtual void AddComponentToList(RobotComponent component)
    {
        if (!CanAddComponent(component))
        {
            return;
        }
        if (!_children.Contains(component))
        {
            _children.Add(component);
        }
    }
    public virtual RobotComponent AddComponent(RobotComponent component)
    {
        component.parent = this;
        return component;
    }
    public RobotComponent AddComponent<T>() where T : RobotComponent, new()
    {
        RobotComponent component = new T();
        return AddComponent(component);
    }
    protected virtual void RemoveComponentFromList(RobotComponent component)
    {
        if (!_children.Contains(component))
        {
            return;
        }
        _children.Remove(component);
        component._parent = null;
    }

    protected virtual bool CanAddComponent(RobotComponent component)
    {
        if (RemainingTech <= component.TechCost)
        {
            Debug.Log("We do not have enough technology");
            return false;
        }
        return true;
    }
    protected int _attack = 0;
    public virtual int Attack
    {
        get
        {
            int ret = _attack;
            foreach (var comp in _children)
            {
                ret += comp.Attack;
            }
            return ret;
        }
    }

    protected int _speed = 0;
    public virtual int Speed
    {
        get
        {
            int ret = _speed;
            foreach (var comp in _children)
            {
                ret += comp.Speed;
            }
            return ret;
        }
    }

    protected int _techCost = 0;
    public virtual int TechCost
    {
        get
        {
            int ret = _techCost;
            foreach (var comp in _children)
            {
                ret += comp.TechCost;
            }
            return ret;
        }
    }

    protected int _maxTech = 0;
    public virtual int RemainingTech
    {
        get
        {
            int ret = _maxTech;
            foreach (var comp in _children)
            {
                ret -= comp.TechCost;
                if (ret < 0)
                {
                    ret = 0;
                    break;
                }
            }
            if (_parent != null && ret > _parent.RemainingTech)
            {
                ret = _parent.RemainingTech;
            }
            return ret;
        }
    }
    
}



public abstract class LeafRobotComponent : RobotComponent
{
    public override RobotComponent AddComponent(RobotComponent component)
    {
        Debug.Log("LeafRobotComponent cannot add component!");
        return null;
    }
    protected override void RemoveComponentFromList(RobotComponent component)
    {
        Debug.Log("LeafRobotComponent cannot add component! So removing component make no sense!");
    }
}

public class RobotBody : RootRobotComponent
{
    public RobotBody()
    {
        _maxTech = 100;
    }
}
public class RobotArm : RobotComponent
{
    public RobotArm()
    {
        _attack = 10;
        _techCost = 20;
        _maxTech = 10;
    }
}

public class RobotLeg : RobotComponent
{
    public RobotLeg()
    {
        _attack = 5;
        _speed = 5;
        _techCost = 20;
        _maxTech = 10;
    }
}


public abstract class RootRobotComponent : RobotComponent
{
    public override RobotComponent parent
    {
        get
        {
            return null;
        }
        set
        {
            Debug.Log("RootRobotComponent cannot has a parent!");
            _parent = null;
        }
    }
}



public class RocketBooster : LeafRobotComponent
{
    public RocketBooster()
    {
        _techCost = 3;
    }
    public override int Speed
    {
        get
        {
            return 2;
        }
    }
}

public class LaserCannon : LeafRobotComponent
{
    public LaserCannon()
    {
        _techCost = 3;
    }
    public override int Speed
    {
        get
        {
            return -1;
        }
    }
    public override int Attack
    {
        get
        {
            return 3;
        }
    }
}




public class Composite : MonoBehaviour
{

    void Start()
    {
        RobotComponent robot = new RobotBody();
        RobotComponent arm1 = new RobotArm();
        RobotComponent arm2 = robot.AddComponent<RobotArm>();
        RobotComponent leg1 = new RobotLeg();
        RobotComponent leg2 = robot.AddComponent<RobotLeg>();
        arm1.AddComponent<LaserCannon>();
        arm2.AddComponent<LaserCannon>();
        leg1.AddComponent<RocketBooster>();
        leg2.AddComponent<RocketBooster>();
        robot.AddComponent<RocketBooster>();
        robot.AddComponent<RocketBooster>();
        robot.AddComponent(arm1);
        robot.AddComponent(leg1);
        robot.AddComponent<LaserCannon>();

        Debug.Log(robot.RemainingTech);
        Debug.Log(robot.Speed);
        Debug.Log(robot.Attack);

    }


}
